﻿using AdvancedDataGridView;
using DbcParserLib;
using DbcParserLib.Observers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TreeGridViewDemo2
{
    public partial class Form1 : Form
    {
        public Font boldFont;
        public JToken root;
        private readonly SimpleFailureObserver m_failureObserver = new SimpleFailureObserver();
        public int pgsTest;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            attachmentColumn.DefaultCellStyle.NullValue = null;

            // load image strip
            this.imageStrip.ImageSize = new System.Drawing.Size(16, 16);
            this.imageStrip.TransparentColor = System.Drawing.Color.Magenta;
            this.imageStrip.ImageSize = new Size(16, 16);
            this.imageStrip.Images.AddStrip(Properties.Resources.vss_icons_16);

            treeGridView1.ImageList = imageStrip;

            // load image strip
            this.imageStrip2.ImageSize = new System.Drawing.Size(16, 16);
            this.imageStrip2.TransparentColor = System.Drawing.Color.Magenta;
            this.imageStrip2.ImageSize = new Size(16, 16);
            this.imageStrip2.Images.AddStrip(Properties.Resources.newGroupPostIconStrip);

            treeGridView2.ImageList = imageStrip2;

            // attachment header cell
            // this.attachmentColumn.HeaderCell = new AttachmentColumnHeader(imageStrip.Images[2]);

            pgsTest = 0;

        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            boldFont = new Font(treeGridView1.DefaultCellStyle.Font, FontStyle.Regular);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
            progressBar1.Value = 0;
            treeGridView1.Nodes.Clear();
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "JSON files (*.json)|*.json";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    //string json = File.ReadAllText(openFileDialog.FileName);
                    //JToken token = JToken.Parse(json);
                    //PopulateTreeView(token, null);

                    using (var reader = new StreamReader(openFileDialog.FileName))
                    using (var jsonReader = new JsonTextReader(reader))
                    {
                        root = JToken.Load(jsonReader);

                        //DisplayTreeView(root, "COVESA Vehicle Signal Specification REL 4.0");
                        DisplayTreeView(root, "COVESA VSS REL 4.0");
                        ExpandNodes(treeGridView1.Nodes, 0, 1);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error loading JSON:" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            timer1.Enabled = false;
            progressBar1.Value = 100;
        }

        private void DisplayTreeView(JToken root, string rootName)
        {
            //treeGridView1.BeginUpdate();
            
            try
            {
                treeGridView1.Nodes.Clear();
                //var tNode = treeGridView1.Nodes[treeGridView1.Nodes.Add(new TreeNode(rootName))];
                var tNode = treeGridView1.Nodes.Add(null, rootName, "VSS", "ETAS-E2E");
                tNode.ImageIndex = 0;
                tNode.DefaultCellStyle.Font = boldFont;
                tNode.Tag = root;
                AddNode(root, tNode);

                //treeView1.ExpandAll();
                // ExpandNodes(treeView1.Nodes, 0, 1);
            }
            finally
            {
                //treeGridView1.EndUpdate();
            }
        }

        private void AddNode(JToken token, TreeGridNode inTreeNode)
        {
            if (token == null)
                return;
            if (token is JValue)
            {
                //var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(token.ToString()))];
                var childNode = inTreeNode.Nodes.Add(null, token.ToString(), "other", @"10/19/2024 00:36 AM");
                childNode.ImageIndex = 1;
                childNode.DefaultCellStyle.Font = boldFont;
                childNode.Tag = token;
            }
            else if (token is JObject)
            {
                var obj = (JObject)token;
                //Check if it's leaf.
                if (obj.ContainsKey("datatype"))
                    return;

                foreach (var property in obj.Properties())
                {
                    switch (property.Name)
                    {
                        case "uuid":
                        case "uint":
                        case "type":
                        case "default":
                        case "comment":
                        case "description":
                            // Console.WriteLine("### IGNORE ####"+ property.Name);
                            break;
                        case "children":
                            JToken sub_jo = property.Value;

                            //Console.WriteLine("####"+sub_jo.ToString());
                            //PrintJsonTokenRecursively(sub_jo, indent + "  "); // 缩进以显示嵌套结构  
                            AddNode(property.Value, inTreeNode);
                            break;
                        default:
                            // Console.WriteLine($" {indent}{property.Name}:");
                            // PrintJsonTokenRecursively(property.Value, indent + "  "); // 缩进以显示嵌套结构  
                            //var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(property.Name))];
                            String dt_item;
                            JToken tmp_jt = property.Value;
                             dt_item = tmp_jt["type"].ToString();

                            var childNode = inTreeNode.Nodes.Add(null, property.Name, dt_item, tmp_jt["description"].ToString());

                            if (tmp_jt["type"].ToString() == "sensor")
                                childNode.ImageIndex = 1;
                            else if (tmp_jt["type"].ToString() == "actuator")
                            {
                                childNode.ImageIndex = 3;
                            }
                            else
                                childNode.ImageIndex = 2;

                            childNode.DefaultCellStyle.Font = boldFont;
                            childNode.Tag = property;
                            AddNode(property.Value, childNode);
                            break;
                    }

                }
            }
            else if (token is JArray)
            {
                var array = (JArray)token;
                for (int i = 0; i < 2;/* array.Count*/ i++)
                {
                    //var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(i.ToString()))];
                    var childNode = inTreeNode.Nodes.Add(null, i.ToString(), "default", @"10/19/2024 00:37 AM");
                    childNode.ImageIndex = 3;
                    childNode.DefaultCellStyle.Font = boldFont;
                    childNode.Tag = array[i];
                    AddNode(array[i], childNode);
                }
            }
            else
            {
                Debug.WriteLine(string.Format("{0} not implemented", token.Type)); // JConstructor, JRaw
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "Open dbc file";
            openFileDialog.FileName = "";
            openFileDialog.Filter = "DBC File|*.dbc";
            openFileDialog.ShowDialog();

            if (openFileDialog.FileName != "")
            {
                timer1.Enabled = true;
                progressBar1.Value = 30;
                LoadDbc(openFileDialog.FileName);
                timer1.Enabled = false;
                progressBar1.Value = 100;
            }
        }

        private void LoadDbc(string fileName)
        {
            Dbc dbc;
            try
            {
                // Comment this line to remove parsing failure management (errors will be silent)
                // You can provide your own IParseObserver implementation to customize parsing failure management
                Parser.SetParsingFailuresObserver(m_failureObserver);

                 dbc = Parser.ParseFromPath(fileName);
                 ShowErrors();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to read dbc file!\n\n{ex}", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                treeGridView2.Nodes.Clear();

                //var tNode = treeGridView2.Nodes.Add("ID", "CANBUS", "root", @"10/19/2005 1:02 AM");
                //tNode.ImageIndex = 0;
                //tNode.DefaultCellStyle.Font = boldFont;

                //var node = tNode.Nodes.Add(null, "Re: Using DataView filter when binding to DataGridView", "tab", @"10/19/2005 1:02 AM");
                //node.ImageIndex = 1;
                TreeGridNode tNode, node;
                foreach (var msg in dbc.Messages)
                {
                    msg.CycleTime(out var cycleTime);
                    //dtMessages.Rows.Add("0x" + msg.ID.ToString("X"), msg.Name, msg.DLC, msg.Transmitter, cycleTime);
                    // Console.WriteLine("CAN MESSAGE ID:{0} NAME:{1} DLC:{2} TX:{3} CT:{4}", "0x" + msg.ID.ToString("X"), msg.Name, msg.DLC, msg.Transmitter, cycleTime);
                    tNode = treeGridView2.Nodes.Add("0x" + msg.ID.ToString("X"), msg.Name, "DLC:"+msg.DLC, "TX ECU:"+ msg.Transmitter, "Peroid:"+cycleTime);
                    tNode.ImageIndex = 0;
                    tNode.DefaultCellStyle.Font = boldFont;

                    foreach (var sig in msg.Signals)
                    {
                        var valueTableString = string.Join("\n", sig.ValueTableMap);
                        node = tNode.Nodes.Add("", msg.Name,"No VSS Mapped", sig.Name, sig.StartBit, sig.Length, sig.ByteOrder, sig.ValueType, sig.InitialValue, sig.Factor, sig.Offset, sig.Minimum, sig.Maximum, sig.Unit, valueTableString, sig.Comment);
                        node.ImageIndex = 1;
                    }

                    //treeView1.ExpandAll();
                    // ExpandNodes(treeView1.Nodes, 0, 1);
                }
            }
            finally
            {
                //treeGridView1.EndUpdate();
            }
        }
        private void ShowErrors()
        {
            var errors = m_failureObserver.GetErrorList();
            if (errors.Count > 0)
            {
                MessageBox.Show(string.Join(Environment.NewLine, errors), "Parsing failures!", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void treeGridView2_DragDrop(object sender, DragEventArgs e)
        {
            // 提取拖放的数据  
            string dragData = e.Data.GetData(typeof(string)) as string;
            if (dragData != null)
            {
                //MessageBox.Show(dragData);

                // 获取鼠标在DataGridView上的位置  
                Point clientPoint = treeGridView2.PointToClient(new Point(e.X, e.Y));

                // 转换为单元格坐标  
                DataGridView.HitTestInfo hit = treeGridView2.HitTest(clientPoint.X, clientPoint.Y);

                // 检查是否命中了单元格  
                if (hit.Type == DataGridViewHitTestType.Cell)
                {
                    if (hit.ColumnIndex == 2)
                        // 获取命中的单元格并更新其值  
                        treeGridView2[hit.ColumnIndex, hit.RowIndex].Value = dragData;
                    else
                        MessageBox.Show("Please drag to VSS column!");
                }


            }
        }

        private void treeGridView2_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void treeGridView2_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        private void treeGridView1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                TreeGridView.HitTestInfo hit = treeGridView1.HitTest(e.X, e.Y);

                if(hit.Type == DataGridViewHitTestType.Cell)
                {
                    string vssPath = GetNodePath(treeGridView1.CurrentNode);
                    treeGridView2.DoDragDrop(vssPath, DragDropEffects.Move);
                    //treeGridView1.Rows[hit.RowIndex].Cells[hit.ColumnIndex].Value.ToString()
                }
            }
        }

        private void treeGridView2_MouseUp(object sender, MouseEventArgs e)
        {
            if (treeGridView2.ClientRectangle.Contains(e.Location))
            {
                // 确定目标单元格的索引  
                int targetColumnIndex = treeGridView2.HitTest(e.X, e.Y).ColumnIndex;
                int targetRowIndex = treeGridView2.HitTest(e.X, e.Y).RowIndex;

                if (targetColumnIndex != -1 && targetRowIndex != -1)
                {
                    // 将值复制到目标单元格  
                    //targetDataGridView[targetColumnIndex, targetRowIndex].Value = draggedCell.Value;
                   // MessageBox.Show("C:" + targetColumnIndex.ToString() + " R:" + targetRowIndex.ToString());

                    // 清理拖动状态  
                    //draggedCell = null;
                }
            }
        }

        private void treeGridView2_MouseMove(object sender, MouseEventArgs e)
        {

        }

        private string GetNodePath(TreeGridNode node)
        {
            if (node == null) return string.Empty;

            List<string> pathList = new List<string>();
            string tmp;
            while (node.Parent!=null)
            {
                tmp = node.Cells[1].Value.ToString();
                //MessageBox.Show(tmp);
                pathList.Add(tmp); // 将节点名称添加到列表的开头  
                node = node.Parent; // 向上移动到父节点  AverageSpeed
            }

            // 反转列表以获取正确的路径顺序（从根到当前节点）  
            pathList.Reverse();
            pathList.RemoveAt(0);
            // 使用特定的分隔符（如"\"）连接路径列表中的字符串  
            string path = string.Join(".", pathList);

            return path;
        }

        private void treeGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            //description
            if (treeGridView1.Columns[e.ColumnIndex].Name == "description")
            {
                e.CellStyle.BackColor = Color.LightGray;
                e.CellStyle.ForeColor = Color.Black;
            }
            //Type
            if (treeGridView1.Columns[e.ColumnIndex].Name == "Type")
            {
                string myType="";
                if(e.Value != null)
                    myType = e.Value.ToString();

                switch (myType)
                {
                    case "sensor":
                        e.CellStyle.BackColor = Color.Yellow;
                        e.CellStyle.ForeColor = Color.Black;
                        break;
                    case "actuator":
                        e.CellStyle.BackColor = Color.DarkGreen;
                        e.CellStyle.ForeColor = Color.Blue;
                        break;
                    default:
                        e.CellStyle.BackColor = Color.LightGoldenrodYellow;
                        e.CellStyle.ForeColor = Color.DarkSlateBlue;
                        break;
                }
 
            }
        }

        private void treeGridView2_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            //valueTableString
            if (treeGridView2.Columns[e.ColumnIndex].Name == "valueTableString")
            {
                e.CellStyle.BackColor = Color.LightGoldenrodYellow;
                e.CellStyle.ForeColor = Color.DarkOrange;
            }
            if (treeGridView2.Columns[e.ColumnIndex].Name == "signalName")
            {
                string myType = "";
                if (e.Value != null)
                    myType = e.Value.ToString();

                if (myType.IndexOf("ECU") > -1)
                {
                    e.CellStyle.BackColor = Color.DarkBlue;
                    e.CellStyle.ForeColor = Color.WhiteSmoke;
                }
                else { 

                    e.CellStyle.BackColor = Color.LightPink;
                    e.CellStyle.ForeColor = Color.DarkBlue;
                }
            }
            //ValueType
            if (treeGridView2.Columns[e.ColumnIndex].Name == "ValueType")
            {
                string myType = "";
                if (e.Value != null)
                    myType = e.Value.ToString();

                switch (myType)
                {
                    case "Unsigned":
                        e.CellStyle.BackColor = Color.Yellow;
                        e.CellStyle.ForeColor = Color.Black;
                        break;
                    case "Signed":
                        e.CellStyle.BackColor = Color.DarkGreen;
                        e.CellStyle.ForeColor = Color.Blue;
                        break;
                    default:
                        e.CellStyle.BackColor = Color.LightGray;
                        e.CellStyle.ForeColor = Color.DarkSlateBlue;
                        break;
                }

            }
            //mappedVSS
            if (treeGridView2.Columns[e.ColumnIndex].Name == "mappedVSS")
            {
                string myType = "";
                if (e.Value != null)
                    myType = e.Value.ToString();

                if (myType.IndexOf("ehicle") > -1)
                {
                    e.CellStyle.BackColor = Color.Green;
                    e.CellStyle.ForeColor = Color.White;
                }
                else if (myType == "No VSS Mapped")
                {
                    e.CellStyle.BackColor = Color.LightCoral;
                    e.CellStyle.ForeColor = Color.DarkMagenta;
                }
                else
                {
                    e.CellStyle.BackColor = Color.LightCyan;
                    e.CellStyle.ForeColor = Color.Black;
                }
                

            }
        }
        void ExpandNodes(TreeGridNodeCollection nodes, int depth, int maxDepth)
        {
            foreach (TreeGridNode node in nodes)
            {
                // 如果当前深度小于或等于最大深度，则展开节点  
                if (depth <= maxDepth)
                {
                    node.Expand(); // 展开节点  

                    // 如果需要继续展开下一级，则递归调用  
                    if (depth < maxDepth && node.Nodes.Count > 0)
                    {
                        ExpandNodes(node.Nodes, depth + 1, maxDepth);
                    }
                }
            }
        }

        private void treeGridView1_Paint(object sender, PaintEventArgs e)
        {
            // Draw background image
            //Image backgroundImage = Properties.Resources.vss_logo; // Replace with your image name
            //e.Graphics.DrawImage(backgroundImage, treeGridView1.ClientRectangle);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            pgsTest++;
            progressBar1.Value = pgsTest;

            if (pgsTest >= 100)
                pgsTest = 0;
        }

        private async void btnValidate_Click(object sender, EventArgs e)
        {
            ProgressDialog pgsDlg = new ProgressDialog();
            pgsDlg.Show();

            await Task.Run(() => {
                for (int i = 0; i <= 100; i++) {
                    pgsDlg.Invoke((MethodInvoker)(() => pgsDlg.UpdateProgress(i)));
                    System.Threading.Thread.Sleep(5);
                }
            });

            pgsDlg.Close();
            MessageBox.Show("Validation passed!");
        }

        private void btnAutoMapping_Click(object sender, EventArgs e)
        {
            TreeGridNodeCollection nodes = treeGridView2.Nodes;
            foreach (TreeGridNode node in nodes)
            {
                string ecu_name = node.Cells[3].Value.ToString();
                 ecu_name = ecu_name.Split(':')[1];
                TreeGridNodeCollection sigNodes = node.Nodes;
                foreach (TreeGridNode subNode in sigNodes)
                {
                    string vss_mapped = subNode.Cells[2].Value.ToString();
                    if (vss_mapped.IndexOf("VSS") > -1)
                        subNode.Cells[2].Value = "Vehicle." + ecu_name +"." + subNode.Cells[1].Value + "." + subNode.Cells[3].Value ;
                }
            }
        }

        public class VssDbcMappingNode
        {
            public string VSS_Path { get; set; }
            public string CANBUS_Signal { get; set;  }
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            TreeGridNodeCollection nodes = treeGridView2.Nodes;
            int cnt = 0;
            List<VssDbcMappingNode> lstMapping = new List<VssDbcMappingNode>();

            foreach (TreeGridNode node in nodes)
            {
                TreeGridNodeCollection sigNodes = node.Nodes;
                foreach (TreeGridNode subNode in sigNodes)
                {
                    string vss_mapped = subNode.Cells[2].Value.ToString();
                    string dbc_signal = subNode.Cells[3].Value.ToString();
                    VssDbcMappingNode tmpNode = new VssDbcMappingNode();
                    tmpNode.VSS_Path = vss_mapped;
                    tmpNode.CANBUS_Signal = dbc_signal;
                    lstMapping.Add(tmpNode);
                    //if(vss_mapped.IndexOf("Vehicle")>-1)
                    //    MessageBox.Show(subNode.Cells[3].Value.ToString());
                    cnt++;

                }
            }

            // 显示保存文件对话框  
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "JSON Files (*.json)|*.json"; // 设置文件过滤器  
            saveFileDialog.Title = "Save JSON File"; // 设置对话框标题  

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 序列化对象为JSON字符串  
                //string json = JsonConvert.SerializeObject(data, Formatting.Indented); // 使用缩进使JSON更易读  
                string tmpJson = JsonConvert.SerializeObject(lstMapping, Formatting.Indented);
                // 写入文件  
                try
                {
                    File.WriteAllText(saveFileDialog.FileName, tmpJson);
                    MessageBox.Show("JSON data saved successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"An error occurred while saving the file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            //MessageBox.Show(node.Cells[1].Value.ToString());
        }
    }
}
